/*
 * main.cpp
 * This file is part of Quarto
 *
 * Copyright (C) 2012 - Ian Liu Rodrigues <ian.liu88@gmail.com>
 *
 * Quarto is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Quarto is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Quarto. If not, see <http://www.gnu.org/licenses/>.
 */

#include <game.hpp>
#include <iostream>
#include <cstdlib>

using namespace br_unicamp;

class AscBoard : public Board {
 public:
  AscBoard()
      : Board()
  {
  }

  void showBoard(void) const
  {
    for (int i = 0; i < 4; i++) {
      for (int j = 0; j < 4; j++) {
        const Piece *p = get(i*4 + j);
        if (p)
          std::cout << "  " << p->toString();
        else
          std::cout << "  ---";
      }
      std::cout << "\n";
    }
    std::cout << "\n";
  }
};

class ScanfStrategy : public PlayerStrategy {
 public:
  ScanfStrategy()
  {
  }

  const Piece* askPiece(const PieceBag& bag, const Board& board)
  {
    char str[5];
    const Piece *p = 0;
    while (p == 0) {
      std::cin >> str;
      unsigned long tmp = strtoul(str, NULL, 2);
      unsigned char code = tmp;
      p = bag.find(code);
    }
    return p;
  }

  int askPlace(const PieceBag& bag, const Board& board, const Piece& piece)
  {
    int place;
    const Piece *p;
    do {
      std::cin >> place;
      p = board.get(place);
    } while (p != 0);
    return place;
  }
};

class AscPieceBag : public PieceBag {
 public:
  void showPieces(void) const
  {
    for (int i = 0; i < 16; i++) {
      const Piece *p = get(i);
      if (p)
        std::cout << "  " << p->toString();
      else
        std::cout << "  ---";
    }
    std::cout << "\n";
  }
};

class AscGameFactory : public GameFactory {
 public:
  PieceBag *getAllPieces(void) const
  {
    return new AscPieceBag();
  }

  Board *getEmptyBoard(void) const
  {
    return new AscBoard();
  }
};

class AscGame : public Game {
 public:
  AscGame(Player *p1, Player *p2, AscGameFactory *factory)
      : Game(p1, p2, factory)
  {
  }

 protected:
  void onPieceRequest(const Player& player, const PieceBag& bag)
  {
    std::cout << player.getName() << ", choose a piece from: ";
    bag.showPieces();
  }

  void onPlaceRequest(const Player& player, const Board& board,
                      const PieceBag& bag)
  {
    std::cout << player.getName() << ", choose a place from: ";
  }

  void onGameFinish(const Player* winner)
  {
    if (winner)
      std::cout << winner->getName() << " is the Winner!\n";
    else
      std::cout << "Its a tie!\n";
  }
};

std::string getPlayerName(const char *msg)
{
  char name[256];

  std::cout << msg;
  std::cin.getline(name, sizeof name);

  return std::string(name);
}

class DumbStrategy : public PlayerStrategy {
 public:
  const Piece* askPiece(const PieceBag& bag, const Board& board)
  {
    for (int i = 0; i < 16; i++) {
      const Piece *p = bag.get(i);
      if (p)
        return p;
    }
    return 0;
  }

  int askPlace(const PieceBag& bag, const Board& board, const Piece& piece)
  {
    int max_row = 0;
    int max_col = 0;
    int row = 0;
    int col = 0;
    const Piece *four[4];
    for (int i = 0; i < 4; i++) {
      board.getBoardRow(i, four);
      int tmp1 = 0;
      for (int j = 0; j < 4; j++) {
        if (four[j] == 0)
          continue;
        if (Piece::isSimilar(piece, *four[j]))
          tmp1++;
      }

      board.getBoardCol(i, four);
      int tmp2 = 0;
      for (int j = 0; j < 4; j++) {
        if (four[j] == 0)
          continue;
        if (Piece::isSimilar(piece, *four[j]))
          tmp2++;
      }

      if (tmp1 > max_row) {
        max_row = tmp1;
        row = i;
      }
      if (tmp2 > max_col) {
        max_col = tmp2;
        col = i;
      }
    }

    int pos;
    if (max_row > max_col) {
      board.getBoardRow(row, four);
      if (four[col] == 0) {
        pos = row * 4 + col;
        return pos;
      } else {
        for (int k = 0; k < 4; k++)
          if (four[k] == 0)
            return row * 4 + k;
      }
    } else {
      board.getBoardCol(col, four);
      if (four[row] == 0) {
        pos = row * 4 + col;
        return pos;
      } else {
        for (int k = 0; k < 4; k++)
          if (four[k] == 0)
            return k * 4 + col;
      }
    }
    return 0;
  }
};

int main(int argc, char *argv[]) {
  std::string n1 = getPlayerName("Player 1, choose your name: ");
  //std::string n2 = getPlayerName("Player 2, choose your name: ");

  AscGameFactory factory;
  ScanfStrategy scanf_strategy;
  DumbStrategy dumb_strategy;
  PlayerStrategy *strategy;

  strategy = &scanf_strategy;
  Player p1(n1, strategy);

  strategy = &dumb_strategy;
  Player p2(std::string("Computer"), strategy);

  AscGame game(&p1, &p2, &factory);
  game.run();

  return 0;
}
